package org.redmagic.dao;

import java.util.Date;
import java.util.Iterator;
import java.util.Set;

import org.redmagic.api.HistoryDao;
import org.redmagic.common.Hierarchy;
import org.redmagic.common.MagicProperty;
import org.redmagic.common.MagicRequest;
import org.redmagic.common.MagicResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;

@Repository
public class MongoHistoryDao implements HistoryDao {

	private static final Logger LOGGER = LoggerFactory.getLogger(MongoHistoryDao.class);
	private static final String DATABASE_NAME = "magic";
	private static final String HISTORY_COLLECTION_NAME = "history";
	
	private final DBCollection history;
	
	@Autowired
	public MongoHistoryDao(MongoClient mongoClient) {
		this.history = mongoClient.getDB(DATABASE_NAME).getCollection(HISTORY_COLLECTION_NAME);
	}

	@Override
	public void logActivity(MagicRequest magicRequest, MagicResponse magicResponse, String remoteHost) {
		try {
			tryLogActivity(magicRequest, magicResponse, remoteHost);
		} catch (JsonProcessingException e) {
			LOGGER.error("Failed to write activity to history", e);
		}
	}
	
	private void tryLogActivity(MagicRequest request, MagicResponse response, String remoteHost) throws JsonProcessingException {
		DBObject activity = new BasicDBObject();
		logTime(activity);
		logRemoteHost(activity, remoteHost);
		logRequest(activity, request);
		logResponse(activity, response);
		logFullyResolved(activity, request.getPlaceholders().size() == response.getResolvedProperties().size());

		history.insert(activity);
	}
	
	private void logTime(DBObject activity) {
		activity.put("time", new Date());
	}
	
	private void logRemoteHost(DBObject activity, String remoteHost) {
		activity.put("remote_host", remoteHost);
	}
	
	private void logRequest(DBObject activity, MagicRequest request) {
		logPlaceholders(activity, request.getPlaceholders());
		logHierarchy(activity, request.getHierarchy());
		logGroup(activity, request.getGroup());
	}
	
	private void logPlaceholders(DBObject activity, Set<String> placeholders) {
		BasicDBList placeholdersJson = new BasicDBList();
		for (String placeholder : placeholders) {
			placeholdersJson.add(placeholder);
		}
		activity.put("placeholders", placeholdersJson);
	}
	
	private void logHierarchy(DBObject activity, Hierarchy hierarchy) {
		BasicDBList levelsJson = new BasicDBList();
		Iterator<Set<String>> tagsIterator = hierarchy.iterator();
		while (tagsIterator.hasNext()) {
			BasicDBList tagsJson = new BasicDBList();
			for (String tag : tagsIterator.next()) {
				tagsJson.add(tag);
			}
			levelsJson.add(tagsJson);
		}
		activity.put("hierarchy", levelsJson);
	}
	
	private void logGroup(DBObject activity, String group) {
		activity.put("group", group);
	}
	
	private void logResponse(DBObject activity, MagicResponse response) {
		BasicDBList properties = new BasicDBList();
		for (MagicProperty property : response.getResolvedProperties()) {
			BasicDBObjectBuilder builder = BasicDBObjectBuilder.start()
					.add("name", property.getName())
					.add("value", property.getValue());
			
			if (property.getEncoding() != "UTF-8") { //FIXME
				builder.add("ENCODING", property.getEncoding());
			}
					
			properties.add(builder.get());
		}
		activity.put("response", properties);
	}
	
	private void logFullyResolved(DBObject activity, boolean isFullyResolved) {
		activity.put("fully_resolved", isFullyResolved);
	}
	
}
